// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/background_sync/background_sync_manager.h"

#include <stdint.h>

#include <memory>
#include <utility>

#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/test/mock_entropy_provider.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/background_sync/background_sync_network_observer.h"
#include "content/browser/background_sync/background_sync_status.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/background_sync_parameters.h"
#include "content/public/browser/permission_type.h"
#include "content/public/test/background_sync_test_util.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/mock_background_sync_controller.h"
#include "content/test/mock_permission_manager.h"
#include "content/test/test_background_sync_manager.h"
#include "net/base/network_change_notifier.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"

namespace content {

namespace {

    using ::testing::_;
    using ::testing::Return;

    const char kPattern1[] = "https://example.com/a";
    const char kPattern2[] = "https://example.com/b";
    const char kScript1[] = "https://example.com/a/script.js";
    const char kScript2[] = "https://example.com/b/script.js";

    void RegisterServiceWorkerCallback(bool* called,
        int64_t* store_registration_id,
        ServiceWorkerStatusCode status,
        const std::string& status_message,
        int64_t registration_id)
    {
        EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
        *called = true;
        *store_registration_id = registration_id;
    }

    void FindServiceWorkerRegistrationCallback(
        scoped_refptr<ServiceWorkerRegistration>* out_registration,
        ServiceWorkerStatusCode status,
        scoped_refptr<ServiceWorkerRegistration> registration)
    {
        EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
        *out_registration = std::move(registration);
    }

    void UnregisterServiceWorkerCallback(bool* called,
        ServiceWorkerStatusCode code)
    {
        EXPECT_EQ(SERVICE_WORKER_OK, code);
        *called = true;
    }

    void DispatchSyncSuccessfulCallback(
        int* count,
        const scoped_refptr<ServiceWorkerVersion>& active_version,
        const ServiceWorkerVersion::StatusCallback& callback)
    {
        *count += 1;
        callback.Run(SERVICE_WORKER_OK);
    }

    void DispatchSyncFailedCallback(
        int* count,
        const scoped_refptr<ServiceWorkerVersion>& active_version,
        const ServiceWorkerVersion::StatusCallback& callback)
    {
        *count += 1;
        callback.Run(SERVICE_WORKER_ERROR_FAILED);
    }

    void DispatchSyncDelayedCallback(
        int* count,
        ServiceWorkerVersion::StatusCallback* out_callback,
        const scoped_refptr<ServiceWorkerVersion>& active_version,
        const ServiceWorkerVersion::StatusCallback& callback)
    {
        *count += 1;
        *out_callback = callback;
    }

} // namespace

class BackgroundSyncManagerTest : public testing::Test {
public:
    BackgroundSyncManagerTest()
        : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP)
        , network_change_notifier_(net::NetworkChangeNotifier::CreateMock())
    {
        sync_options_1_.tag = "foo";
        sync_options_1_.network_state = NETWORK_STATE_ONLINE;

        sync_options_2_.tag = "bar";
        sync_options_2_.network_state = NETWORK_STATE_ONLINE;
    }

    void SetUp() override
    {
        // Don't let the tests be confused by the real-world device connectivity
        background_sync_test_util::SetIgnoreNetworkChangeNotifier(true);

        // TODO(jkarlin): Create a new object with all of the necessary SW calls
        // so that we can inject test versions instead of bringing up all of this
        // extra SW stuff.
        helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));

        std::unique_ptr<MockPermissionManager> mock_permission_manager(
            new testing::NiceMock<MockPermissionManager>());
        ON_CALL(*mock_permission_manager,
            GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
            .WillByDefault(Return(blink::mojom::PermissionStatus::GRANTED));
        helper_->browser_context()->SetPermissionManager(
            std::move(mock_permission_manager));

        // Create a StoragePartition with the correct BrowserContext so that the
        // BackgroundSyncManager can find the BrowserContext through it.
        storage_partition_impl_.reset(new StoragePartitionImpl(
            helper_->browser_context(), base::FilePath(), nullptr, nullptr, nullptr,
            nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
            nullptr, nullptr, nullptr, nullptr));
        helper_->context_wrapper()->set_storage_partition(
            storage_partition_impl_.get());

        SetMaxSyncAttemptsAndRestartManager(1);

        // Wait for storage to finish initializing before registering service
        // workers.
        base::RunLoop().RunUntilIdle();
        RegisterServiceWorkers();
    }

    void TearDown() override
    {
        // Restore the network observer functionality for subsequent tests
        background_sync_test_util::SetIgnoreNetworkChangeNotifier(false);
    }

    void RegisterServiceWorkers()
    {
        bool called_1 = false;
        bool called_2 = false;
        helper_->context()->RegisterServiceWorker(
            GURL(kPattern1), GURL(kScript1), NULL,
            base::Bind(&RegisterServiceWorkerCallback, &called_1,
                &sw_registration_id_1_));

        helper_->context()->RegisterServiceWorker(
            GURL(kPattern2), GURL(kScript2), NULL,
            base::Bind(&RegisterServiceWorkerCallback, &called_2,
                &sw_registration_id_2_));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(called_1);
        EXPECT_TRUE(called_2);

        // Hang onto the registrations as they need to be "live" when
        // calling BackgroundSyncManager::Register.
        helper_->context_wrapper()->FindReadyRegistrationForId(
            sw_registration_id_1_, GURL(kPattern1).GetOrigin(),
            base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_1_));

        helper_->context_wrapper()->FindReadyRegistrationForId(
            sw_registration_id_2_, GURL(kPattern1).GetOrigin(),
            base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_2_));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(sw_registration_1_);
        EXPECT_TRUE(sw_registration_2_);
    }

    void SetNetwork(net::NetworkChangeNotifier::ConnectionType connection_type)
    {
        net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
            connection_type);
        if (test_background_sync_manager_) {
            BackgroundSyncNetworkObserver* network_observer = test_background_sync_manager_->GetNetworkObserverForTesting();
            network_observer->NotifyManagerIfNetworkChangedForTesting(
                connection_type);
            base::RunLoop().RunUntilIdle();
        }
    }

    void StatusAndRegistrationCallback(
        bool* was_called,
        BackgroundSyncStatus status,
        std::unique_ptr<BackgroundSyncRegistration> registration)
    {
        *was_called = true;
        callback_status_ = status;
        callback_registration_ = std::move(registration);
    }

    void StatusAndRegistrationsCallback(
        bool* was_called,
        BackgroundSyncStatus status,
        std::unique_ptr<ScopedVector<BackgroundSyncRegistration>> registrations)
    {
        *was_called = true;
        callback_status_ = status;
        callback_registrations_ = std::move(registrations);
    }

    void StatusCallback(bool* was_called, BackgroundSyncStatus status)
    {
        *was_called = true;
        callback_status_ = status;
    }

protected:
    void CreateBackgroundSyncManager()
    {
        test_background_sync_manager_ = new TestBackgroundSyncManager(helper_->context_wrapper());
        background_sync_manager_.reset(test_background_sync_manager_);

        test_clock_ = new base::SimpleTestClock();
        background_sync_manager_->set_clock(base::WrapUnique(test_clock_));

        // Many tests do not expect the sync event to fire immediately after
        // register (and cleanup up the sync registrations).  Tests can control when
        // the sync event fires by manipulating the network state as needed.
        // NOTE: The setup of the network connection must happen after the
        //       BackgroundSyncManager has been created.
        SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    }

    void InitBackgroundSyncManager()
    {
        test_background_sync_manager_->DoInit();
        base::RunLoop().RunUntilIdle();
    }

    void SetupBackgroundSyncManager()
    {
        CreateBackgroundSyncManager();
        InitBackgroundSyncManager();
    }

    void SetupCorruptBackgroundSyncManager()
    {
        CreateBackgroundSyncManager();
        test_background_sync_manager_->set_corrupt_backend(true);
        InitBackgroundSyncManager();
    }

    void SetupDelayedBackgroundSyncManager()
    {
        CreateBackgroundSyncManager();
        test_background_sync_manager_->set_delay_backend(true);
        InitBackgroundSyncManager();
    }

    void DeleteBackgroundSyncManager()
    {
        background_sync_manager_.reset();
        test_background_sync_manager_ = nullptr;
        test_clock_ = nullptr;
    }

    bool Register(const BackgroundSyncRegistrationOptions& sync_options)
    {
        return RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options);
    }

    bool RegisterWithServiceWorkerId(
        int64_t sw_registration_id,
        const BackgroundSyncRegistrationOptions& options)
    {
        bool was_called = false;
        background_sync_manager_->Register(
            sw_registration_id, options,
            base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                base::Unretained(this), &was_called));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(was_called);
        return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
    }

    MockPermissionManager* GetPermissionManager()
    {
        return static_cast<MockPermissionManager*>(
            helper_->browser_context()->GetPermissionManager());
    }

    bool GetRegistration(
        const BackgroundSyncRegistrationOptions& registration_options)
    {
        return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
            registration_options);
    }

    bool GetRegistrationWithServiceWorkerId(
        int64_t sw_registration_id,
        const BackgroundSyncRegistrationOptions& registration_options)
    {
        bool was_called = false;
        background_sync_manager_->GetRegistrations(
            sw_registration_id,
            base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
                base::Unretained(this), &was_called));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(was_called);

        if (callback_status_ == BACKGROUND_SYNC_STATUS_OK) {
            for (auto iter = callback_registrations_->begin();
                 iter < callback_registrations_->end(); ++iter) {
                if ((*iter)->options()->tag == registration_options.tag) {
                    // Transfer the matching registration out of the vector into
                    // callback_registration_ for testing.
                    callback_registration_.reset(*iter);
                    callback_registrations_->weak_erase(iter);
                    return true;
                }
            }
        }
        return false;
    }

    bool GetRegistrations()
    {
        return GetRegistrationsWithServiceWorkerId(sw_registration_id_1_);
    }

    bool GetRegistrationsWithServiceWorkerId(int64_t sw_registration_id)
    {
        bool was_called = false;
        background_sync_manager_->GetRegistrations(
            sw_registration_id,
            base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
                base::Unretained(this), &was_called));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(was_called);

        return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
    }

    MockBackgroundSyncController* GetController()
    {
        return static_cast<MockBackgroundSyncController*>(
            helper_->browser_context()->GetBackgroundSyncController());
    }

    void StorageRegistrationCallback(ServiceWorkerStatusCode result)
    {
        callback_sw_status_code_ = result;
    }

    void UnregisterServiceWorker(uint64_t sw_registration_id)
    {
        bool called = false;
        helper_->context()->UnregisterServiceWorker(
            PatternForSWId(sw_registration_id),
            base::Bind(&UnregisterServiceWorkerCallback, &called));
        base::RunLoop().RunUntilIdle();
        EXPECT_TRUE(called);
    }

    GURL PatternForSWId(int64_t sw_id)
    {
        EXPECT_TRUE(sw_id == sw_registration_id_1_ || sw_id == sw_registration_id_2_);
        return sw_id == sw_registration_id_1_ ? GURL(kPattern1) : GURL(kPattern2);
    }

    void SetupForSyncEvent(
        const TestBackgroundSyncManager::DispatchSyncCallback& callback)
    {
        test_background_sync_manager_->set_dispatch_sync_callback(callback);
        SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    }

    void InitSyncEventTest()
    {
        SetupForSyncEvent(
            base::Bind(DispatchSyncSuccessfulCallback, &sync_events_called_));
    }

    void InitFailedSyncEventTest()
    {
        SetupForSyncEvent(
            base::Bind(DispatchSyncFailedCallback, &sync_events_called_));
    }

    void InitDelayedSyncEventTest()
    {
        SetupForSyncEvent(base::Bind(DispatchSyncDelayedCallback,
            &sync_events_called_, &sync_fired_callback_));
    }

    void RegisterAndVerifySyncEventDelayed(
        const BackgroundSyncRegistrationOptions& sync_options)
    {
        int sync_events_called = sync_events_called_;
        EXPECT_TRUE(sync_fired_callback_.is_null());

        EXPECT_TRUE(Register(sync_options));

        EXPECT_EQ(sync_events_called + 1, sync_events_called_);
        EXPECT_TRUE(GetRegistration(sync_options_1_));
        EXPECT_FALSE(sync_fired_callback_.is_null());
    }

    void DeleteServiceWorkerAndStartOver()
    {
        helper_->context()->ScheduleDeleteAndStartOver();
        base::RunLoop().RunUntilIdle();
    }

    int MaxTagLength() const { return BackgroundSyncManager::kMaxTagLength; }

    void SetMaxSyncAttemptsAndRestartManager(int max_sync_attempts)
    {
        BackgroundSyncParameters* parameters = GetController()->background_sync_parameters();
        parameters->max_sync_attempts = max_sync_attempts;

        // Restart the BackgroundSyncManager so that it updates its parameters.
        SetupBackgroundSyncManager();
    }

    TestBrowserThreadBundle browser_thread_bundle_;
    std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
    std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
    std::unique_ptr<BackgroundSyncManager> background_sync_manager_;
    std::unique_ptr<StoragePartitionImpl> storage_partition_impl_;
    TestBackgroundSyncManager* test_background_sync_manager_ = nullptr;
    base::SimpleTestClock* test_clock_ = nullptr;

    int64_t sw_registration_id_1_;
    int64_t sw_registration_id_2_;
    scoped_refptr<ServiceWorkerRegistration> sw_registration_1_;
    scoped_refptr<ServiceWorkerRegistration> sw_registration_2_;

    BackgroundSyncRegistrationOptions sync_options_1_;
    BackgroundSyncRegistrationOptions sync_options_2_;

    // Callback values.
    BackgroundSyncStatus callback_status_ = BACKGROUND_SYNC_STATUS_OK;
    std::unique_ptr<BackgroundSyncRegistration> callback_registration_;
    std::unique_ptr<ScopedVector<BackgroundSyncRegistration>>
        callback_registrations_;
    ServiceWorkerStatusCode callback_sw_status_code_ = SERVICE_WORKER_OK;
    int sync_events_called_ = 0;
    ServiceWorkerVersion::StatusCallback sync_fired_callback_;
};

TEST_F(BackgroundSyncManagerTest, Register)
{
    EXPECT_TRUE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegistrationIntact)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_STREQ(sync_options_1_.tag.c_str(),
        callback_registration_->options()->tag.c_str());
    EXPECT_TRUE(callback_registration_->IsValid());
}

TEST_F(BackgroundSyncManagerTest, RegisterWithoutLiveSWRegistration)
{
    sw_registration_1_ = nullptr;
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, RegisterWithoutActiveSWRegistration)
{
    sw_registration_1_->UnsetVersion(sw_registration_1_->active_version());
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, RegisterBadBackend)
{
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_FALSE(Register(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(false);
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegisterPermissionDenied)
{
    GURL expected_origin = GURL(kPattern1).GetOrigin();
    MockPermissionManager* mock_permission_manager = GetPermissionManager();

    EXPECT_CALL(*mock_permission_manager,
        GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
            expected_origin, expected_origin))
        .WillOnce(testing::Return(blink::mojom::PermissionStatus::DENIED));
    EXPECT_FALSE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegisterPermissionGranted)
{
    GURL expected_origin = GURL(kPattern1).GetOrigin();
    MockPermissionManager* mock_permission_manager = GetPermissionManager();

    EXPECT_CALL(*mock_permission_manager,
        GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
            expected_origin, expected_origin))
        .WillOnce(testing::Return(blink::mojom::PermissionStatus::GRANTED));
    EXPECT_TRUE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, TwoRegistrations)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationNonExisting)
{
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationExisting)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationBadBackend)
{
    EXPECT_TRUE(Register(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(Register(sync_options_2_));
    // Registration should have discovered the bad backend and disabled the
    // BackgroundSyncManager.
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(false);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsZero)
{
    EXPECT_TRUE(GetRegistrations());
    EXPECT_EQ(0u, callback_registrations_->size());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsOne)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistrations());

    EXPECT_EQ(1u, callback_registrations_->size());
    sync_options_1_.Equals(*(*callback_registrations_)[0]->options());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsTwo)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_TRUE(GetRegistrations());

    EXPECT_EQ(2u, callback_registrations_->size());
    sync_options_1_.Equals(*(*callback_registrations_)[0]->options());
    sync_options_2_.Equals(*(*callback_registrations_)[1]->options());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsBadBackend)
{
    EXPECT_TRUE(Register(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_TRUE(GetRegistrations());
    EXPECT_FALSE(Register(sync_options_2_));
    // Registration should have discovered the bad backend and disabled the
    // BackgroundSyncManager.
    EXPECT_FALSE(GetRegistrations());
    test_background_sync_manager_->set_corrupt_backend(false);
    EXPECT_FALSE(GetRegistrations());
}

TEST_F(BackgroundSyncManagerTest, Reregister)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, ReregisterSecond)
{
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RegisterMaxTagLength)
{
    sync_options_1_.tag = std::string(MaxTagLength(), 'a');
    EXPECT_TRUE(Register(sync_options_1_));

    sync_options_2_.tag = std::string(MaxTagLength() + 1, 'b');
    EXPECT_FALSE(Register(sync_options_2_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_NOT_ALLOWED, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, RegistrationIncreasesId)
{
    EXPECT_TRUE(Register(sync_options_1_));
    BackgroundSyncRegistration::RegistrationId cur_id = callback_registration_->id();

    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_LT(cur_id, callback_registration_->id());
}

TEST_F(BackgroundSyncManagerTest, RebootRecovery)
{
    EXPECT_TRUE(Register(sync_options_1_));

    SetupBackgroundSyncManager();

    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RebootRecoveryTwoServiceWorkers)
{
    EXPECT_TRUE(
        RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options_1_));
    EXPECT_TRUE(
        RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_2_));

    SetupBackgroundSyncManager();

    EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
        sync_options_1_));
    EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
        sync_options_2_));
    EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
        sync_options_1_));
    EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
        sync_options_2_));

    EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
        sync_options_1_));
    EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
        sync_options_2_));

    EXPECT_TRUE(
        RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options_2_));
    EXPECT_TRUE(
        RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, InitWithBadBackend)
{
    SetupCorruptBackgroundSyncManager();

    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, SequentialOperations)
{
    // Schedule Init and all of the operations on a delayed backend. Verify that
    // the operations complete sequentially.
    SetupDelayedBackgroundSyncManager();

    bool register_called = false;
    bool get_registrations_called = false;
    test_background_sync_manager_->Register(
        sw_registration_id_1_, sync_options_1_,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
            base::Unretained(this), &register_called));
    test_background_sync_manager_->GetRegistrations(
        sw_registration_id_1_,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
            base::Unretained(this), &get_registrations_called));

    base::RunLoop().RunUntilIdle();
    // Init should be blocked while loading from the backend.
    EXPECT_FALSE(register_called);
    EXPECT_FALSE(get_registrations_called);

    test_background_sync_manager_->ResumeBackendOperation();
    base::RunLoop().RunUntilIdle();
    // Register should be blocked while storing to the backend.
    EXPECT_FALSE(register_called);
    EXPECT_FALSE(get_registrations_called);

    test_background_sync_manager_->ResumeBackendOperation();
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(register_called);
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, callback_status_);
    // GetRegistrations should run immediately as it doesn't write to disk.
    EXPECT_TRUE(get_registrations_called);
}

TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorker)
{
    EXPECT_TRUE(Register(sync_options_1_));
    UnregisterServiceWorker(sw_registration_id_1_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest,
    UnregisterServiceWorkerDuringSyncRegistration)
{
    EXPECT_TRUE(Register(sync_options_1_));

    test_background_sync_manager_->set_delay_backend(true);
    bool callback_called = false;
    test_background_sync_manager_->Register(
        sw_registration_id_1_, sync_options_2_,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
            base::Unretained(this), &callback_called));

    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(callback_called);
    UnregisterServiceWorker(sw_registration_id_1_);

    test_background_sync_manager_->ResumeBackendOperation();
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(callback_called);
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);

    test_background_sync_manager_->set_delay_backend(false);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DeleteAndStartOverServiceWorkerContext)
{
    EXPECT_TRUE(Register(sync_options_1_));
    DeleteServiceWorkerAndStartOver();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterBrowserRestart)
{
    EXPECT_TRUE(Register(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_FALSE(Register(sync_options_2_));

    // The manager is now disabled and not accepting new requests until browser
    // restart or notification that the storage has been wiped.
    test_background_sync_manager_->set_corrupt_backend(false);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(Register(sync_options_2_));

    // Simulate restarting the browser by creating a new BackgroundSyncManager.
    SetupBackgroundSyncManager();
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterDeleteAndStartOver)
{
    EXPECT_TRUE(Register(sync_options_1_));
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_FALSE(Register(sync_options_2_));

    // The manager is now disabled and not accepting new requests until browser
    // restart or notification that the storage has been wiped.
    test_background_sync_manager_->set_corrupt_backend(false);
    DeleteServiceWorkerAndStartOver();

    RegisterServiceWorkers();

    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsId)
{
    BackgroundSyncRegistration reg_1;
    BackgroundSyncRegistration reg_2;

    EXPECT_TRUE(reg_1.Equals(reg_2));
    reg_2.set_id(reg_1.id() + 1);
    EXPECT_TRUE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsTag)
{
    BackgroundSyncRegistration reg_1;
    BackgroundSyncRegistration reg_2;
    EXPECT_TRUE(reg_1.Equals(reg_2));
    reg_2.options()->tag = "bar";
    EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsNetworkState)
{
    BackgroundSyncRegistration reg_1;
    BackgroundSyncRegistration reg_2;
    EXPECT_TRUE(reg_1.Equals(reg_2));
    reg_1.options()->network_state = NETWORK_STATE_ANY;
    reg_2.options()->network_state = NETWORK_STATE_ONLINE;
    EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, StoreAndRetrievePreservesValues)
{
    InitDelayedSyncEventTest();
    BackgroundSyncRegistrationOptions options;

    // Set non-default values for each field.
    options.tag = "foo";
    EXPECT_NE(NETWORK_STATE_AVOID_CELLULAR, options.network_state);
    options.network_state = NETWORK_STATE_AVOID_CELLULAR;

    // Store the registration.
    EXPECT_TRUE(Register(options));

    // Simulate restarting the sync manager, forcing the next read to come from
    // disk.
    SetupBackgroundSyncManager();

    EXPECT_TRUE(GetRegistration(options));
    EXPECT_TRUE(options.Equals(*callback_registration_->options()));
}

TEST_F(BackgroundSyncManagerTest, EmptyTagSupported)
{
    sync_options_1_.tag = "";
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_TRUE(sync_options_1_.Equals(*callback_registration_->options()));
}

TEST_F(BackgroundSyncManagerTest, FiresOnRegistration)
{
    InitSyncEventTest();

    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptFails)
{
    InitDelayedSyncEventTest();
    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    // Reregister the event mid-sync
    EXPECT_TRUE(Register(sync_options_1_));

    // The first sync attempt fails.
    sync_fired_callback_.Run(SERVICE_WORKER_ERROR_FAILED);
    base::RunLoop().RunUntilIdle();

    // It should fire again since it was reregistered mid-sync.
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, ReregisterMidSyncFirstAttemptSucceeds)
{
    InitDelayedSyncEventTest();
    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    // Reregister the event mid-sync
    EXPECT_TRUE(Register(sync_options_1_));

    // The first sync event succeeds.
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    base::RunLoop().RunUntilIdle();

    // It should fire again since it was reregistered mid-sync.
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, OverwritePendingRegistration)
{
    InitFailedSyncEventTest();

    // Prevent the first sync from running so that it stays in a pending state.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Overwrite the first sync. It should still be pending.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Verify that it only gets to run once.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DisableWhilePending)
{
    InitDelayedSyncEventTest();
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_TRUE(Register(sync_options_1_));

    // Corrupting the backend should result in the manager disabling itself on the
    // next operation.
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_FALSE(Register(sync_options_2_));

    test_background_sync_manager_->set_corrupt_backend(false);
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(0, sync_events_called_);
}

TEST_F(BackgroundSyncManagerTest, DisableWhileFiring)
{
    InitDelayedSyncEventTest();

    // Register a one-shot that pauses mid-fire.
    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    // Corrupting the backend should result in the manager disabling itself on the
    // next operation.
    test_background_sync_manager_->set_corrupt_backend(true);
    EXPECT_FALSE(Register(sync_options_2_));
    test_background_sync_manager_->set_corrupt_backend(false);

    // Successfully complete the firing event. We can't verify that it actually
    // completed but at least we can test that it doesn't crash.
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    base::RunLoop().RunUntilIdle();
}

TEST_F(BackgroundSyncManagerTest, FiresOnNetworkChange)
{
    InitSyncEventTest();

    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(0, sync_events_called_);
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, MultipleRegistrationsFireOnNetworkChange)
{
    InitSyncEventTest();

    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_EQ(0, sync_events_called_);
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_2_));

    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);

    EXPECT_EQ(2, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, FiresOnManagerRestart)
{
    InitSyncEventTest();

    // Initially the event won't run because there is no network.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(0, sync_events_called_);
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Simulate closing the browser.
    DeleteBackgroundSyncManager();

    // The next time the manager is started, the network is good.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    SetupBackgroundSyncManager();
    InitSyncEventTest();

    // The event should have fired.
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, FailedRegistrationShouldBeRemoved)
{
    InitFailedSyncEventTest();

    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, FailedRegistrationReregisteredAndFires)
{
    InitFailedSyncEventTest();

    // The initial sync event fails.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));

    InitSyncEventTest();

    // Reregistering should cause the sync event to fire again, this time
    // succeeding.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(2, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DelayMidSync)
{
    InitDelayedSyncEventTest();

    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    // Finish firing the event and verify that the registration is removed.
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1, sync_events_called_);
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, BadBackendMidSync)
{
    InitDelayedSyncEventTest();

    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    test_background_sync_manager_->set_corrupt_backend(true);
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    base::RunLoop().RunUntilIdle();

    // The backend should now be disabled because it couldn't unregister the
    // one-shot.
    EXPECT_FALSE(Register(sync_options_2_));
    EXPECT_FALSE(
        RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorkerMidSync)
{
    InitDelayedSyncEventTest();

    RegisterAndVerifySyncEventDelayed(sync_options_1_);
    UnregisterServiceWorker(sw_registration_id_1_);

    sync_fired_callback_.Run(SERVICE_WORKER_OK);

    // The backend isn't disabled, but the first service worker registration is
    // gone.
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_TRUE(
        RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, KillManagerMidSync)
{
    InitDelayedSyncEventTest();

    RegisterAndVerifySyncEventDelayed(sync_options_1_);

    // Create a new manager which should fire the sync again on init.
    SetupBackgroundSyncManager();
    InitSyncEventTest();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_EQ(2, sync_events_called_);
}

TEST_F(BackgroundSyncManagerTest, RegisterWithoutMainFrame)
{
    test_background_sync_manager_->set_has_main_frame_provider_host(false);
    EXPECT_FALSE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegisterExistingWithoutMainFrame)
{
    EXPECT_TRUE(Register(sync_options_1_));
    test_background_sync_manager_->set_has_main_frame_provider_host(false);
    EXPECT_FALSE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DefaultParameters)
{
    *GetController()->background_sync_parameters() = BackgroundSyncParameters();
    // Restart the BackgroundSyncManager so that it updates its parameters.
    SetupBackgroundSyncManager();

    EXPECT_EQ(BackgroundSyncParameters(),
        *test_background_sync_manager_->background_sync_parameters());
}

TEST_F(BackgroundSyncManagerTest, OverrideParameters)
{
    BackgroundSyncParameters* parameters = GetController()->background_sync_parameters();
    parameters->disable = true;
    parameters->max_sync_attempts = 100;
    parameters->initial_retry_delay = base::TimeDelta::FromMinutes(200);
    parameters->retry_delay_factor = 300;
    parameters->min_sync_recovery_time = base::TimeDelta::FromMinutes(400);
    parameters->max_sync_event_duration = base::TimeDelta::FromMinutes(500);

    // Restart the BackgroundSyncManager so that it updates its parameters.
    SetupBackgroundSyncManager();

    // Check that the manager is disabled
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);

    const BackgroundSyncParameters* manager_parameters = test_background_sync_manager_->background_sync_parameters();
    EXPECT_EQ(*parameters, *manager_parameters);
}

TEST_F(BackgroundSyncManagerTest, DisablingFromControllerKeepsRegistrations)
{
    EXPECT_TRUE(Register(sync_options_1_));

    BackgroundSyncParameters* parameters = GetController()->background_sync_parameters();
    parameters->disable = true;

    // Restart the BackgroundSyncManager so that it updates its parameters.
    SetupBackgroundSyncManager();
    EXPECT_FALSE(GetRegistration(sync_options_1_)); // fails because disabled

    // Reenable the BackgroundSyncManager on next launch
    parameters->disable = false;

    // Restart the BackgroundSyncManager so that it updates its parameters.
    SetupBackgroundSyncManager();
    EXPECT_TRUE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DisabledPermanently)
{
    BackgroundSyncParameters* parameters = GetController()->background_sync_parameters();
    parameters->disable = true;

    // Restart the BackgroundSyncManager so that it updates its parameters.
    SetupBackgroundSyncManager();

    // Check that the manager is disabled
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);

    // If the service worker is wiped and the manager is restarted, the manager
    // should stay disabled.
    DeleteServiceWorkerAndStartOver();
    RegisterServiceWorkers();
    EXPECT_FALSE(Register(sync_options_1_));
    EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, NotifyBackgroundSyncRegistered)
{
    // Verify that the BackgroundSyncController is informed of registrations.
    EXPECT_EQ(0, GetController()->registration_count());
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(1, GetController()->registration_count());
    EXPECT_EQ(GURL(kPattern1).GetOrigin().spec(),
        GetController()->registration_origin().spec());
}

TEST_F(BackgroundSyncManagerTest, WakeBrowserCalled)
{
    InitDelayedSyncEventTest();

    // The BackgroundSyncManager should declare in initialization
    // that it doesn't need to be woken up since it has no registrations.
    EXPECT_LT(0, GetController()->run_in_background_count());
    EXPECT_FALSE(GetController()->run_in_background_enabled());

    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
    EXPECT_FALSE(GetController()->run_in_background_enabled());

    // Register a one-shot but it can't fire due to lack of network, wake up is
    // required.
    Register(sync_options_1_);
    EXPECT_TRUE(GetController()->run_in_background_enabled());

    // Start the event but it will pause mid-sync due to
    // InitDelayedSyncEventTest() above.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
    EXPECT_TRUE(GetController()->run_in_background_enabled());
    EXPECT_EQ(test_background_sync_manager_->background_sync_parameters()
                  ->min_sync_recovery_time,
        base::TimeDelta::FromMilliseconds(
            GetController()->run_in_background_min_ms()));

    // Finish the sync.
    sync_fired_callback_.Run(SERVICE_WORKER_OK);
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetController()->run_in_background_enabled());
}

TEST_F(BackgroundSyncManagerTest, OneAttempt)
{
    SetMaxSyncAttemptsAndRestartManager(1);
    InitFailedSyncEventTest();

    // It should permanently fail after failing once.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, TwoAttempts)
{
    SetMaxSyncAttemptsAndRestartManager(2);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(test_background_sync_manager_->delayed_task().is_null());

    // Make sure the delay is reasonable.
    EXPECT_LT(base::TimeDelta::FromMinutes(1),
        test_background_sync_manager_->delayed_task_delta());
    EXPECT_GT(base::TimeDelta::FromHours(1),
        test_background_sync_manager_->delayed_task_delta());

    // Fire again and this time it should permanently fail.
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, ThreeAttempts)
{
    SetMaxSyncAttemptsAndRestartManager(3);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(test_background_sync_manager_->delayed_task().is_null());

    // The second run will fail but it will setup a timer to try again.
    base::TimeDelta first_delta = test_background_sync_manager_->delayed_task_delta();
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Verify that the delta grows for each attempt.
    EXPECT_LT(first_delta, test_background_sync_manager_->delayed_task_delta());

    // The third run will permanently fail.
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, WaitsFullDelayTime)
{
    SetMaxSyncAttemptsAndRestartManager(2);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(test_background_sync_manager_->delayed_task().is_null());

    // Fire again one second before it's ready to retry. Expect it to reschedule
    // the delay timer for one more second.
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta() - base::TimeDelta::FromSeconds(1));
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_EQ(base::TimeDelta::FromSeconds(1),
        test_background_sync_manager_->delayed_task_delta());

    // Fire one second later and it should fail permanently.
    test_clock_->Advance(base::TimeDelta::FromSeconds(1));
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RetryOnBrowserRestart)
{
    SetMaxSyncAttemptsAndRestartManager(2);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Simulate restarting the browser after sufficient time has passed.
    base::TimeDelta delta = test_background_sync_manager_->delayed_task_delta();
    CreateBackgroundSyncManager();
    InitFailedSyncEventTest();
    test_clock_->Advance(delta);
    InitBackgroundSyncManager();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RescheduleOnBrowserRestart)
{
    SetMaxSyncAttemptsAndRestartManager(2);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Simulate restarting the browser before the retry timer has expired.
    base::TimeDelta delta = test_background_sync_manager_->delayed_task_delta();
    CreateBackgroundSyncManager();
    InitFailedSyncEventTest();
    test_clock_->Advance(delta - base::TimeDelta::FromSeconds(1));
    InitBackgroundSyncManager();
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_EQ(base::TimeDelta::FromSeconds(1),
        test_background_sync_manager_->delayed_task_delta());
}

TEST_F(BackgroundSyncManagerTest, RetryIfClosedMidSync)
{
    InitDelayedSyncEventTest();

    RegisterAndVerifySyncEventDelayed(sync_options_1_);
    // The time delta is the recovery timer.
    base::TimeDelta delta = test_background_sync_manager_->delayed_task_delta();

    // Simulate restarting the browser after the recovery time, the event should
    // fire once and then fail permanently.
    CreateBackgroundSyncManager();
    InitFailedSyncEventTest();
    test_clock_->Advance(delta);
    InitBackgroundSyncManager();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, AllTestsEventuallyFire)
{
    SetMaxSyncAttemptsAndRestartManager(3);
    InitFailedSyncEventTest();

    // The first run will fail but it will setup a timer to try again.
    EXPECT_TRUE(Register(sync_options_1_));

    // Run it a second time.
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();

    base::TimeDelta delay_delta = test_background_sync_manager_->delayed_task_delta();

    // Create a second registration, which will fail and setup a timer.
    EXPECT_TRUE(Register(sync_options_2_));
    EXPECT_GT(delay_delta, test_background_sync_manager_->delayed_task_delta());

    while (!test_background_sync_manager_->delayed_task().is_null()) {
        test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
        test_background_sync_manager_->delayed_task().Run();
        test_background_sync_manager_->ClearDelayedTask();
        base::RunLoop().RunUntilIdle();
    }

    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, LastChance)
{
    SetMaxSyncAttemptsAndRestartManager(2);
    InitFailedSyncEventTest();

    EXPECT_TRUE(Register(sync_options_1_));
    EXPECT_EQ(blink::mojom::BackgroundSyncEventLastChance::IS_NOT_LAST_CHANCE,
        test_background_sync_manager_->last_chance());
    EXPECT_TRUE(GetRegistration(sync_options_1_));

    // Run it again.
    test_clock_->Advance(test_background_sync_manager_->delayed_task_delta());
    test_background_sync_manager_->delayed_task().Run();
    base::RunLoop().RunUntilIdle();
    EXPECT_FALSE(GetRegistration(sync_options_1_));
    EXPECT_EQ(blink::mojom::BackgroundSyncEventLastChance::IS_LAST_CHANCE,
        test_background_sync_manager_->last_chance());
}

} // namespace content
